/*
 * Copyright 2009 Gal Dolber
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.dragdrop.client;

import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetUtil;
import com.google.gwt.user.dragdrop.client.impl.DragImpl;

public class DragController extends AbstractDragController {

	/**
	 * Add drag capabilities to the widget
	 * 
	 * @param widget
	 *            Widget
	 * @return Controller
	 */
	public static DragController make(Widget widget) {
		return make(widget, null, new DragImpl());
	}

	/**
	 * Add drag capabilities to the widget with a custom implementation
	 * 
	 * @param widget
	 *            Widget
	 * @param impl
	 *            Implementation
	 * @return Controller
	 */
	public static DragController make(Widget widget, HasDragHandlers impl) {
		return make(widget, null, impl);
	}

	/**
	 * Add drag capabilities to the widget with a custom implementation
	 * 
	 * @param widget
	 *            Widget
	 * @param handler
	 *            Handler
	 * @param impl
	 *            Implementation
	 * @return Controller
	 */
	public static DragController make(Widget widget, Widget handler,
			HasDragHandlers impl) {
		return new DragController(widget, handler, impl);
	}

	// Handler
	protected Widget handler;

	// Implementation
	private HasDragHandlers impl;

	// Widget
	protected Widget widget;

	// Handler registrations
	private HandlerRegistration mouseDownHandler = null;
	private HandlerRegistration mouseMoveHandler = null;
	private HandlerRegistration mouseUpHandler = null;

	DragController(Widget w, Widget h, HasDragHandlers impl) {
		widget = w;
		this.impl = impl;

		// Find delegated or assign the widget as handler
		if (h == null) {
			try {
				handler = ((DelegateDragHandler) w).getDragDelegate();
			} catch (Exception e) {
				handler = w;
			}
		} else {
			handler = h;
		}

		// Enable drag handlers
		enableDrag();
	}

	/**
	 * Disable drag handlers
	 */
	public void disableDrag() {
		if (mouseDownHandler != null)
			mouseDownHandler.removeHandler();
		if (mouseMoveHandler != null)
			mouseMoveHandler.removeHandler();
		if (mouseUpHandler != null)
			mouseUpHandler.removeHandler();
	}

	/**
	 * Enable drag handlers
	 */
	public void enableDrag() {
		mouseDownHandler = WidgetUtil.addDomHandler(handler, this,
				MouseDownEvent.getType());
		mouseMoveHandler = WidgetUtil.addDomHandler(handler, this,
				MouseMoveEvent.getType());
		mouseUpHandler = WidgetUtil.addDomHandler(handler, this, MouseUpEvent
				.getType());
	}

	/**
	 * Get the handler
	 */
	public Widget getHandler() {
		return handler;
	}

	/**
	 * Get the widget
	 */
	public Widget getWidget() {
		return widget;
	}

	/**
	 * If has dragged
	 */
	private boolean hasDragged = false;
	
	@Override
	public void onMouseDown(MouseDownEvent event) {
		super.onMouseDown(event);

		hasDragged = false;
		
		if (!isMouseDown()) {
			return;
		}

		// Call implementation
		impl.onDragStart(this);
	}

	@Override
	public void onMouseMove(MouseMoveEvent event) {
		super.onMouseMove(event);

		hasDragged = true;
		
		if (!isMouseDown()) {
			return;
		}

		// Call implementation
		impl.onDragMove(this);
	}

	@Override
	public void onMouseUp(MouseUpEvent event) {
		super.onMouseUp(event);

		// Call implementation
		impl.onDragEnd(this);
	}

	@Override
	public String toString() {
		return impl.toString();
	}

	/**
	 * @return True if has dragged
	 */
	public boolean hasDragged() {
		return hasDragged;
	}
}
